using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;


namespace XLFrame.NodeEditor
{
    /// <summary>
    /// 节点数据层
    /// </summary>
    public class NodeDataBase
    {
        /// <summary>
        /// 节点坐标
        /// </summary>
        [SerializeField]
        public Vector2 Position;

        /// <summary>
        /// 节点类型
        /// </summary>
        public string NodeType { get; set; }

        /// <summary>
        /// 其他自定义数据
        /// </summary>
        [JsonProperty]
        public AttributesData Attributes { get; private set; } = new AttributesData();
        
        /// <summary>
        /// 节点中添加的逻辑类
        /// </summary>
        [JsonProperty]
        public List<string> NodeLogicData { get;private set; } = new List<string>();
        
        /// <summary>
        /// 节点中添加的样式类
        /// </summary>
        [JsonProperty]
        public List<NodeStyleData> NodeStyleDatas { get;private set; } = new List<NodeStyleData>();

        /// <summary>
        /// 输出端口信息,包含连接关系 主要用于恢复连接关系和动态添加端口保存与加载
        /// </summary>
        [JsonProperty]
        private Dictionary<string, PortOutputViewData> OutputPortDatas = new Dictionary<string, PortOutputViewData>();

        /// <summary>
        /// 输入端口信息,不包含连接关系 主要用于动态添加端口保存与加载
        /// </summary>
        [JsonProperty]
        private Dictionary<string, PortViewData> InputPortDatas = new Dictionary<string, PortViewData>();


        /// <summary>
        /// 用于标识节点唯一性，在负责存储这个类的总类查询引用，不可重复
        /// </summary>
        [JsonProperty]
        public string GUID { get;private set; }
        public NodeDataBase()
        {
            if (string.IsNullOrEmpty(GUID))
            {
                GUID = System.Guid.NewGuid().ToString();
            }
        }

        #region 克隆自身

        public NodeDataBase Clone()
        {
            return Json.DeserializeObject(Json.SerializeObject(this),GetType()) as NodeDataBase;
        }

        #endregion

        #region 端口数据相关

        /// <summary>
        /// 判断端口是否已经输出信息中
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public bool PortInOutputPortDatas(string guid)
        {
            return OutputPortDatas.ContainsKey(guid);
        }
        
        /// <summary>
        /// 判断端口是否已经添加到输入信息中
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public bool PortInInputPortDatas(string guid)
        {
            return InputPortDatas.ContainsKey(guid);
        }
        
        

        /// <summary>
        /// 获取输出端口信息
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public PortOutputViewData GetOutputPort(string guid)
        {
            return OutputPortDatas.GetValueOrDefault(guid);
        }

        /// <summary>
        /// 添加一个端口信息
        /// </summary>
        /// <param name="portData"></param>
        public bool AddOutputPort(PortOutputViewData portData)
        {
            if (PortInOutputPortDatas(portData.GUID)) return false;
            OutputPortDatas.Add(portData.GUID, portData);
            return true;

        }

        /// <summary>
        /// 添加一个输入端口
        /// </summary>
        /// <param name="protData"></param>
        /// <returns></returns>
        public bool AddInputPort(PortViewData protData)
        {
            if (InputPortDatas.ContainsKey(protData.GUID))
            {
                return false;
            }
            InputPortDatas.Add(protData.GUID, protData);
            return true;
        }

        /// <summary>
        /// 移除一个输入端口
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public bool RemoveInputPort(string guid)
        {
            return InputPortDatas.Remove(guid);
        }
        
        /// <summary>
        /// 移除一个输出端口
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public bool RemoveOutputPort(string guid)
        {
            return OutputPortDatas.Remove(guid);
        }

        /// <summary>
        /// 通过guid移除一个端口
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public bool RemovePort(string guid)
        {
            return RemoveOutputPort(guid) || RemoveInputPort(guid);
        }
        
        /// <summary>
        /// 返回所有端口信息
        /// </summary>
        /// <returns></returns>
        public IEnumerable<PortOutputViewData> GetOutputPort()
        {
            return OutputPortDatas.Values;
        }

        /// <summary>
        /// 获取所有输入端口信息
        /// </summary>
        /// <returns></returns>
        public IEnumerable<PortViewData> GetInputPort()
        {
            return InputPortDatas.Values;
        }
        #endregion

    }

    /// <summary>
    /// 端口基础信息,记录端口的信息,不包含端口的数据
    /// </summary>
    public class PortViewData
    {
        /// <summary>
        /// 端口唯一ID
        /// </summary>
        [JsonProperty]
        public string GUID { get; private set; }
        /// <summary>
        /// 接口名称
        /// </summary>
        [JsonProperty]
        public string PortName { get; private set; }
        /// <summary>
        /// 接口类型    
        /// </summary>
        [JsonProperty]
        public string PortType { get; private set; }
        
        /// <summary>
        /// 容器ID 表明当前端口属于哪一个容器,节点还是某一个样式容器中
        /// </summary>
        [JsonProperty]
        public string ContainerID { get; private set; }

        /// <summary>
        /// 端口支持的连接形式
        /// </summary>
        [JsonProperty, JsonConverter(typeof(StringEnumConverter))]
        public Capacity PortCapacity { get; private set; }

        /// <summary>
        /// 端口的输出方向
        /// </summary>
        [JsonProperty, JsonConverter(typeof(StringEnumConverter))]
        public Direction PortDirection { get; private set; }

        public enum Direction
        {
            Input,
            Output
        }

        public enum Capacity
        {
            Single,
            Multi
        }

        public PortViewData()
        {

        }
#if UNITY_EDITOR
        public PortViewData(UnityEditor.Experimental.GraphView.Port port,string containerID)
        {
            PortName = port.portName;
            PortType = $"{port.portType.FullName}, {port.portType.Assembly.GetName().Name}";
            GUID = port.name;

            PortCapacity = (Capacity)port.capacity;
            PortDirection = (Direction)port.direction;
            
            ContainerID = containerID;
        }
#endif
    }

    /// <summary>
    /// 端口输出数据
    /// </summary>
    public class PortOutputViewData : PortViewData
    {
        /// <summary>
        /// 节点连接关系
        /// </summary>
        public Dictionary<string, NodeLinkData> NodeLinkDatas = new Dictionary<string, NodeLinkData>();
#if UNITY_EDITOR
        public PortOutputViewData(UnityEditor.Experimental.GraphView.Port port,string containerID) : 
            base(port,containerID)
        {
            
        }
#endif

        public PortOutputViewData() : base()
        {

        }

        /// <summary>
        /// 添加一个连接关系
        /// </summary>
        /// <param name="nodeLinkData"></param>
        public void Add(NodeLinkData nodeLinkData)
        {
            NodeLinkDatas.Add(nodeLinkData.EdgeGuid,nodeLinkData);
        }

        /// <summary>
        /// 移除一个连接关系
        /// </summary>
        /// <param name="edgeGuid"></param>
        public void Remove(string edgeGuid)
        {
            NodeLinkDatas.Remove(edgeGuid);
        }
    }
    /// <summary>
    /// 节点连接关系(自身是out接口视角)
    /// </summary>
    public class NodeLinkData
    {
        /// <summary>
        /// 连接的边的guid
        /// </summary>
        [JsonProperty]
        public string EdgeGuid { get; private set; }

        /// <summary>
        /// 输出到的节点的guid
        /// </summary>
        [JsonProperty]
        public string InputNodeGuid { get; private set; }

        /// <summary>
        /// 节点的端口名称
        /// </summary>
        [JsonProperty]
        public string PortGuid { get; private set; }

        public NodeLinkData(string inputNodeGuid, string portGuid)
        {
            InputNodeGuid = inputNodeGuid;
            PortGuid = portGuid;
        }

        /// <summary>
        /// 创建时赋值用
        /// </summary>
        public void CreateEdgeGuid()
        {
            EdgeGuid = System.Guid.NewGuid().ToString();
        }
    }
}

